package www.wen.com.common.lib.base.module

import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import www.wen.com.common.R
import www.wen.com.common.lib.data.entities.LoadingDialog
import www.wen.com.common.lib.data.entities.LoadingDialogStateType
import www.wen.com.common.lib.data.entities.Result
import www.wen.com.common.lib.data.entities.UiStateCustom
import www.wen.com.common.lib.data.repository.AppDataManager
import www.wen.com.common.lib.extension.getString

/**
 * @author WEN
 * @Description: 这个类是方便写扩展函数，之前的基类没有AppDataManager这个对象
 * @date 2020/11/2 17:35
 */
open class BaseApiViewModel @ViewModelInject constructor(var appDataManager: AppDataManager) : BaseViewModel(), LifecycleObserver {


    fun <T> requestUniversal(
            viewModelScope: CoroutineScope,
            request: suspend (appDataManager: AppDataManager) -> Result<T>,
            tipLoading: String = getString(R.string.loading),
            tipSuccess: String = getString(R.string.loading_succeeded),
            tipFail: String = getString(R.string.network_anomaly),
            isShowDialogTip: Boolean = false,
            isShowToastTip: Boolean = false,
            isShowErrorDialogTip: Boolean = false,
            isShowErrorToastTip: Boolean = true,
            resultFailCall: ((String) -> Unit)? = null,
            resultSuccessCall: ((T) -> Unit)? = null,
    ) {
        viewModelScope.launch {
            loading.value = UiStateCustom(
                    stateData = LoadingDialog(
                            tipLoading,
                            LoadingDialogStateType.LOADING
                    )
            )
            val result = request.invoke(appDataManager)
            if (result is Result.Success) {
                loading.value = UiStateCustom(
                        stateData = LoadingDialog(
                                tip = tipSuccess,
                                loadingDialogStateType = LoadingDialogStateType.SUCCESS,
                                isShowDialogTip = isShowDialogTip,
                                isShowToastTip = isShowToastTip,
                                action = { resultSuccessCall?.invoke(result.data) }
                        )
                )
            } else if (result is Result.Error) {
                loading.value = UiStateCustom(
                        stateData = LoadingDialog(
                                tip = result.exception.message ?: tipFail,
                                loadingDialogStateType = LoadingDialogStateType.ERROR,
                                isShowDialogTip = isShowErrorDialogTip,
                                isShowToastTip = isShowErrorToastTip,
                                action = { resultFailCall?.invoke(result.exception.message ?: tipFail) }
                        )
                )
            }
        }
    }

    fun <T> requestUniversalFlow(
            universalFlow: (AppDataManager)->Flow<T>,
            tipLoading: String = getString(R.string.loading),
            tipSuccess: String = getString(R.string.loading_succeeded),
            tipFail: String = getString(R.string.network_anomaly),
            isShowDialogTip: Boolean = false,
            isShowToastTip: Boolean = false,
            isShowErrorDialogTip: Boolean = false,
            isShowErrorToastTip: Boolean = true,
            resultFailCall: ((String) -> Unit)? = null,
            resultSuccessCall: ((T) -> Unit)? = null,
    ) {
        viewModelScope.launch {
            universalFlow.invoke(appDataManager)
                    .onStart {
                        loading.value = UiStateCustom(
                                stateData = LoadingDialog(
                                        tipLoading,
                                        LoadingDialogStateType.LOADING
                                )
                        )
                    }
                    .catch { cause ->
                        loading.value = UiStateCustom(
                                stateData = LoadingDialog(
                                        tip = cause.message  ?: tipFail,
                                        loadingDialogStateType = LoadingDialogStateType.ERROR,
                                        isShowDialogTip = isShowErrorDialogTip,
                                        isShowToastTip = isShowErrorToastTip,
                                        action = { resultFailCall?.invoke(cause.message ?: tipFail) }
                                )
                        )
                    }
                    .collect {
                        loading.value = UiStateCustom(
                                stateData = LoadingDialog(
                                        tip = tipSuccess,
                                        loadingDialogStateType = LoadingDialogStateType.SUCCESS,
                                        isShowDialogTip = isShowDialogTip,
                                        isShowToastTip = isShowToastTip,
                                        action = { resultSuccessCall?.invoke(it) }
                                )
                        )
                    }
        }
    }

}